---@class TBS.RuleMgr
local RuleMgr = TBS.CreateSingleton("RuleMgr")
local this = RuleMgr
local TURN_STAGE = {
    team1 = 1,
    team2 = 2,
    team3 = 3,
    team4 = 4,
    boss = 5,
}
local BATTLE_STAGE = {
    none = 0,
    start = 1,
    battling = 2,
    win = 3,
    failed = 4,
    timeOut = 5,
    finished = 6,
}
function RuleMgr.OnCreate()
    this.time = 0
    this.turnCount = 0
    this.isPause = false
    ---@type TBS.Player
    this.boss = nil
    this.battleStage = BATTLE_STAGE.none
    this.stageData = {
        isReleasing = false,
        delayTime = dataTable.getGlobalInt(399)/1000,
        curTime = 0,
        index = 0,
        stage = TURN_STAGE.none,
    }
    ---@type TBS.CommandBase[]
    this.cmdList = {}
    ---@type TBS.CommandBase[]
    this.executeCmdList = {}
    TBS.Battle.RegisterUpdateCallback(this.Update)
end
function RuleMgr.OnDestroy()
    this.executeCmdList = nil
    this.cmdList = nil
end
function RuleMgr.Pause(isPause)
    this.isPause = isPause
end
function RuleMgr.Clear()
    table.clear(this.executeCmdList)
    table.clear(this.cmdList)
end
---战斗开始
function RuleMgr.StartFight()
    this.turnCount = 0
    this.time = 0
    this.isPause = false
    this.stageData.isReleasing = false
    this.stageData.stage = TURN_STAGE.team1
    this.battleStage = BATTLE_STAGE.start
    this.Clear()
end

function RuleMgr.BattleFinished(resultType,reset)
    this.stageData.isReleasing = false
    this.battleStage = BATTLE_STAGE.finished
    this.Pause(true)
    TBS.Battle.BattleFinished(resultType,reset)
end
function RuleMgr.Update(dt)
    if this.isPause then return end
    this.time = this.time + dt
    local data = this.stageData
    if this.battleStage == BATTLE_STAGE.none then
        return
    end
    if this.battleStage == BATTLE_STAGE.start then
        this.battleStage = BATTLE_STAGE.battling
        this.turnCount = 1
        data.curTime = 0
        data.isReleasing = true
        this.AddTurnCmd()
        this.ExecuteCmd()
    elseif this.battleStage == BATTLE_STAGE.battling then

    elseif this.battleStage == BATTLE_STAGE.win then
        this.BattleFinished(TBS.Config.BattleResultType.bossDie,true)
    elseif this.battleStage == BATTLE_STAGE.failed then
        this.BattleFinished(TBS.Config.BattleResultType.groupAllDie,true)
    elseif this.battleStage == BATTLE_STAGE.timeOut then
        this.BattleFinished(TBS.Config.BattleResultType.timeOut,true)
    end
    if data.isReleasing then
        --if data.isWaitingCmdEnd then
            for k,v in pairs(this.executeCmdList) do--等待指令执行完
                --if (v.action == TBS.Config.FightActionType.ATTACK) and not v.isActive then
                if (v.action == TBS.Config.FightActionType.ATTACK or v.action == TBS.Config.FightActionType.BUFF) and not v.isEnd then
                    return
                end
            end
        --end
        data.curTime = data.curTime - dt
        if data.curTime <= 0 then
            if (#this.cmdList == 0) then
                this.turnCount = this.turnCount + 1
                this.AddTurnCmd()
            end
            this.ExecuteCmd()
        end

    end
end
function RuleMgr.AddTurnCmd()

    if this.turnCount > TBS.ReportMgr.turnCount then

        local boss = TBS.ActorMgr.GetBoss()
        if not boss or boss:IsDead() then
            this.battleStage = BATTLE_STAGE.win
            return
        end
        if this.turnCount > TBS.ReportMgr.maxTurn then
            this.battleStage = BATTLE_STAGE.timeOut
            return
        end
        this.battleStage = BATTLE_STAGE.failed
        if this.turnCount > TBS.ReportMgr.maxTurn then
            this.turnCount = TBS.ReportMgr.maxTurn
        end
        FireEvent(TBS.Config.Event.BattleTurnStart,this.turnCount,TBS.ReportMgr.maxTurn)
        return
    end
    local cmdList = TBS.ReportMgr.GetCommandList(this.turnCount)
    if not cmdList then return end
    table.clear(this.cmdList)
    for k,v in pairs(cmdList) do
        table.insert(this.cmdList,v)
    end
end
function RuleMgr.ExecuteCmd()
    table.clear(this.executeCmdList)
    ---@type TBS.CommandRound
    local curCmd
    ---@type TBS.CommandRound
    local nextCmd
    while(true) do
        if #this.cmdList == 0 then
            break
        end
        local cmd = this.cmdList[1]
        if cmd.action == TBS.Config.FightActionType.ROUND then
            if curCmd == nil then
                curCmd = cmd
                if curCmd:IsTurnStart() then
                    local _list = TBS.ActorMgr.GetAllGroups()
                    for k,v in pairs(_list) do
                        for k2,p in pairs(v) do
                            p:TurnStart()
                        end
                    end
                    local _list = TBS.ActorMgr.GetLeaderList()
                    for k,p in pairs(_list) do
                        p:TurnStart()
                    end
                    if curCmd.frame > 1 then
                        TBS.ActorMgr.LeaderTurnStartAll()
                    end
                    FireEvent(TBS.Config.Event.BattleTurnStart,this.turnCount,TBS.ReportMgr.maxTurn)
                end
                if curCmd:IsBossTurn() then
                    local boss = TBS.ActorMgr.GetBoss()
                    boss:TurnStart()
                end
            else
                nextCmd = cmd
                break
            end
        end
        cmd:Execute()
        table.remove(this.cmdList,1)
        table.insert(this.executeCmdList,cmd)
    end
    if curCmd == nil then
        return
    end
    if curCmd:IsTurnStart() then
        return
    end
    if curCmd:IsTurnEnd() then
        FireEvent(TBS.Config.Event.BattleTurnEnd,this.turnCount,TBS.ReportMgr.maxTurn)
    end
    local data = this.stageData
    data.curTime = 0--data.delayTime
    data.isReleasing = true
    data.isWaitingCmdEnd = false
    if nextCmd and (curCmd:GroupTurn() ~= nextCmd:GroupTurn() or nextCmd:IsTurnEnd()) then
        if curCmd:IsBossTurn() or nextCmd:IsBossTurn() then --boss等时间长点
            data.curTime = data.curTime + data.delayTime
        end
        data.isWaitingCmdEnd = true
    end
    --if curCmd:IsTurnEnd() then
    --    data.curTime = 0.3
    --end
end
--跳到指定回合
function RuleMgr.GotoRound(round)
    local turn = 1
    local tb = {}
    local players = TBS.ActorMgr.GetActorList()
    for k,v in pairs(players) do
        tb[v:GetId()] = {hp = v:GetHpMax(),maxHp = v:GetHpMax(),bufferList = {}}
    end
    while(turn < round) do
        local cmdList = TBS.ReportMgr.GetCommandList(turn)
        if cmdList then
            for k,v in pairs(cmdList) do
                if v.action == TBS.Config.FightActionType.DAMAGE then
                    ---@type TBS.CommandDamage
                    local damageCmd = v
                    local p = tb[damageCmd.targetId]
                    if damageCmd.damageType == TBS.Config.DamageType.heal then
                        p.hp = math.min(p.hp + damageCmd.damage,p.maxHp)
                    else
                        p.hp = math.max(0,p.hp - damageCmd.damage)
                    end
                elseif v.action == TBS.Config.FightActionType.BUFF then
                    ---@type TBS.CommandBuff
                    local buffCmd = v
                    local p = tb[buffCmd.targetId]
                    if buffCmd.type == 1 then --移除
                        p.bufferList[buffCmd.buffId] = nil
                    else
                        p.bufferList[buffCmd.buffId] = buffCmd.buffOverlay
                    end
                end
            end
        end
    end
    for k,v in pairs(tb) do
        local player = players[k]
        player:SetHp(v.hp)
        TBS.BufferMgr.RemoveBuff(k,nil,true)
        for buffId,overlay in pairs(v.bufferList) do
            player:AddBuff(buffId,overlay)
        end
    end
end

